package net.zrnecko.km.server;

import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;

import net.zrnecko.km.client.PersistenceService;
import net.zrnecko.km.dto.PlayerDTO;
import net.zrnecko.km.dto.TournamentDTO;
import net.zrnecko.km.entity.Player;
import net.zrnecko.km.entity.Tournament;

import org.dozer.Mapper;

import com.google.inject.Inject;
import com.google.inject.Singleton;

@Singleton
public final class PersistenceServiceImpl implements PersistenceService {

	@Inject
	private Logger log;

	@Inject
	private EntityManagerFactory emfInstance;
	
	@Inject
	private Mapper mapper;

	public PersistenceServiceImpl() {
	}

	private EntityManager em;

	private EntityManagerFactory getEntityManagerFactory() {
		return emfInstance;
	}
	
	private EntityManager getEntityManager() {
		return this.getEntityManagerFactory().createEntityManager();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * net.zrnecko.km.entity.PersistenceService#persistTournament(net.zrnecko
	 * .km.entity.Tournament)
	 */
	public void persistTournament(Tournament tournament) {
		log.info("Persisting tournament" + tournament.toString() + "...");
		em = getEntityManager();
		try {
			// TODO do I need to explicitly mark transaction boundaries?
			// em.getTransaction().begin();
			em.persist(tournament);
			// em.getTransaction().commit();
			log.info("Tournament persisted.");
		} finally {
			em.close();
		}
	}

	public List<TournamentDTO> listTournaments() {
		log.info("Getting tournaments...");
		List<TournamentDTO> tournamentsDto = new ArrayList<TournamentDTO>();
		em = this.getEntityManagerFactory().createEntityManager();
		try {
			List<Tournament> tournaments = em.createNamedQuery(
					"findAllTournaments").getResultList();
			tournaments.size();
			for(Tournament t : tournaments) {
				tournamentsDto.add(mapper.map(t, TournamentDTO.class));
			}

		} finally {
			em.close();
		}
		return tournamentsDto;
	}

	public TournamentDTO getTournamentByTournamentId(int tournamentId) {
		log.info("Getting tournament with tournament id " + tournamentId);
		em = this.getEntityManagerFactory().createEntityManager();
		TournamentDTO tournament;
		try {
			tournament = mapper.map((Tournament) em.createNamedQuery(
					"findTournamentByTourId").setParameter("tournamentId", 27)
					.getSingleResult(), TournamentDTO.class );
		} finally {
			em.close();
		}
		return tournament;

	}

	public void persistTournament(TournamentDTO tournament) {
		log.info("Persisting tournament" + tournament.toString() + "...");
		em = this.getEntityManagerFactory().createEntityManager();
		try {
			// TODO do I need to explicitly mark transaction boundaries?
			// em.getTransaction().begin();
			// TODO tranform through mapper
			Tournament t = new Tournament();
			t.setDate(tournament.getDate());
			t.setTournamentId(tournament.getTournamentId());
			em.persist(t);
			// em.getTransaction().commit();
			log.info("Tournament persisted.");
		} finally {
			em.close();
		}
		// TODO Auto-generated method stub
		
	}

	public void persistPlayer(PlayerDTO player) {
		log.info("Persisting player" + player.toString() + "...");
		em = getEntityManager();
		try {
			Player p = mapper.map(player, Player.class);
			em.persist(p);
			log.info("Player persisted.");
		} finally {
			em.close();
		}
	}
	
	public List<PlayerDTO> listPlayers() {
		log.info("Getting tournaments...");
		List<PlayerDTO> playersDto = new ArrayList<PlayerDTO>();
		em = this.getEntityManagerFactory().createEntityManager();
		try {
			List<Player> players = em.createNamedQuery(
					"findAllPlayers").getResultList();
			players.size();
			for(Player p : players) {
				p.getPlayerHistory().size();
				playersDto.add(mapper.map(p, PlayerDTO.class));
			}
		} finally {
			em.close();
		}
		return playersDto;
	}

}
